//#include "log.h"
#include "modbus_RTU_mast.h"
#include "dev_switch.h"
static modbus_page_t   *dev_page = NULL;
static uint16_t         dev_num = 0;
static uint16_t         Mstart_addr = 0;                    //03读寄存器起始地址缓存 06:写寄存器地址

typedef struct
{
	uint8_t  mod_addr;
    uint8_t  func_code;
    uint16_t Quantity;  //03:数量 06：数值
} ModBus_info;

static void bytes_reverse(void *src, void *dst, int len);
bool check_modbus_frame_valid(uint8_t *p_data, uint8_t len, ModBus_info *info);
unsigned int UART_CRC16_Work(unsigned char *CRC_Buf,unsigned char CRC_Leni);
static int read_AO_res(uint16_t sn, uint16_t start_addr, uint16_t size, uint8_t *p_dst);
static void modbus_data_switch(modbus_table_t *tb, uint8_t *data);
static int white_more_AO_push(uint8_t addr, uint16_t res_addr, uint16_t res_num,
                  uint8_t *value, uint8_t value_len, uint8_t *p_dst);
static int white_more_AO_res(uint16_t sn, uint8_t *p_dst);
static int read_input_AO_res(uint16_t sn, uint16_t start_addr, uint16_t size, uint8_t *p_dst);

void set_modbus_page(modbus_page_t *page, uint16_t num)
{
    dev_page = page;
    dev_num = num;
}

/****************************************************************************
名称: bytes_reverse()
说明: 大小端转换
参数: *src:输入数据
*dst:输出数据
len:数据长度
*****************************************************************************/
static void bytes_reverse(void *src, void *dst, int len)
{
    int i;
    unsigned char *p_src, *p_dst;
    
    p_src = (unsigned char*) src;
    p_dst = (unsigned char*) dst;
    
    for (i = 0; i < len; i++)
        p_dst[i] = p_src[len - 1 - i];
}

/****************************************************************************
名称: UART_CRC16_Work()
说明: CRC16校验程序
参数: 		*CRC_Buf:数据地址
CRC_Leni:数据长度
返回:       CRC_Sumx:校验值
*****************************************************************************/
unsigned int UART_CRC16_Work(unsigned char *CRC_Buf,unsigned char CRC_Leni)
{
	unsigned char i,j;
	unsigned int CRC_Sumx, tem_crc;
	CRC_Sumx=0xFFFF;
	for(i=0;i<CRC_Leni;i++)
	{
		CRC_Sumx^=*(CRC_Buf+i);//异或
		for(j=0;j<8;j++)
		{
			if(CRC_Sumx & 0x01)
			{
				CRC_Sumx>>=1;	
				CRC_Sumx^=0xA001;
			}
			else
			{
				CRC_Sumx>>=1;
			}
		}	
	}
    bytes_reverse(&CRC_Sumx, &tem_crc, 2);
	return (tem_crc);
}

/****************************************************************************
名称: read_AO(void)
说明: 功能码0x03调用
参数: 		           
返回:       
*****************************************************************************/
int read_AO(uint16_t addr_sn, uint16_t start_addr, uint16_t num, uint8_t *p_dst)
{
    uint16_t crc_16;
    uint16_t len = 0;

    if (start_addr == 0 || num == 0 || p_dst == NULL)
        return -1;

    Mstart_addr = start_addr;
    // 8bit addr - 8bit fkt code - n x 8bit data(max n=252) - 16bit CRC LOW/HIGH
    p_dst[len++] = dev_page[addr_sn].md_addr;
    p_dst[len++] = MODBUS_READ_HOLDING_REGISTERS;
    bytes_reverse((uint8_t *)&start_addr, &p_dst[len], 2);
    len += 2;
    bytes_reverse((uint8_t *)&num, &p_dst[len], 2);
    len += 2;
    crc_16 = (uint16_t)UART_CRC16_Work(p_dst, len);
    bytes_reverse((uint8_t *)&crc_16, &p_dst[len], 2);
    //memcpy(&p_dst[len], (uint8_t *)(&crc_16), 2);
    len += 2;

    return len;
}

#include "public_crc16_rtu.h"
/****************************************************************************
名称: read_AO(void)
说明: 功能码0x04调用
参数: 		           
返回:       
*****************************************************************************/
int read_input_AO(uint16_t addr_sn, uint16_t start_addr, uint16_t num, uint8_t *p_dst)
{
    uint16_t crc_16;
    uint16_t len = 0;

    if (start_addr == 0 || num == 0 || p_dst == NULL)
        return -1;

    Mstart_addr = start_addr;

    p_dst[len++] = dev_page[addr_sn].md_addr;              //DevAddr
    p_dst[len++] = 0x04;//MODBUS_READ_INPUT_REGISTERS;     //功能码
    bytes_reverse((uint8_t *)&start_addr, &p_dst[len], 2); //寄存器地址 StAdd（STM32小端模式 p_dst大端保存）
    len += 2;
    bytes_reverse((uint8_t *)&num, &p_dst[len], 2);
    len += 2;

    crc_16 = (uint16_t)UART_CRC16_Work(p_dst, len);
    bytes_reverse((uint8_t *)&crc_16, &p_dst[len], 2);
    len += 2;
    //memcpy(&p_dst[len], (uint8_t *)(&crc_16), 2);
    
    return len;
}

/****************************************************************************
名称: modbus_data_switch()
说明: modbus数据转换
参数: 		           
返回:       
*****************************************************************************/
static void modbus_data_switch(modbus_table_t *tb, uint8_t *data)
{
    uint8_t buf[8];
    float   tem_float;

    if (tb == NULL || tb->offset == NULL)
        return;
    
    if (tb->res_data_type == TLV_FLOAT && tb->rel_data_type == TLV_FLOAT)
    {
        bytes_reverse(data, buf, 4);
        memcpy(&tem_float, buf, sizeof(float));
        tem_float = tem_float * 1.0f / tb->ratio ;
        memcpy(tb->offset, &tem_float, sizeof(float));     //解码出的值赋给tb->offset（PV_modbus_table里的pS1.P_sensor1）
    }
    if (tb->res_data_type == TLV_STRING && tb->rel_data_type == TLV_STRING)
    {
        memcpy(tb->offset, data, tb->num * 2);
    }    
    else if (tb->res_data_type == TLV_USHORT && tb->rel_data_type == TLV_USHORT)
    {
        bytes_reverse(data, buf, 2);
        *(uint16_t *)tb->offset = *(uint16_t *)buf * 1.0 / tb->ratio;
    }
    else if (tb->res_data_type == TLV_USHORT && tb->rel_data_type == TLV_FLOAT)
    {
        bytes_reverse(data, buf, 2);
        tem_float = *(uint16_t *)buf * 1.0 / tb->ratio;
        memcpy(tb->offset, &tem_float, sizeof(float));
    }
    else if (tb->res_data_type == TLV_SHORT && tb->rel_data_type == TLV_FLOAT)
    {
        bytes_reverse(data, buf, 2);
        tem_float = *(int16_t *)buf * 1.0 / tb->ratio;
        memcpy(tb->offset, &tem_float, sizeof(float));
    }    
    else if (tb->res_data_type == TLV_UINT && tb->rel_data_type == TLV_FLOAT)
    {
        bytes_reverse(data, buf, 4);
        tem_float = *(uint32_t *)buf * 1.0 / tb->ratio;
        memcpy(tb->offset, &tem_float, sizeof(float));
    }
    else if (tb->res_data_type == TLV_UINT && tb->rel_data_type == TLV_UINT)
    {
        bytes_reverse(data, buf, 4);
        *(uint32_t *)tb->offset = *(uint32_t *)buf * 1.0 / tb->ratio;
    }
    else if (tb->res_data_type == TLV_INT && tb->rel_data_type == TLV_FLOAT)
    {
        bytes_reverse(data, buf, 4);
        tem_float = *(int32_t *)buf * 1.0 / tb->ratio;
        memcpy(tb->offset, &tem_float, sizeof(float));
    }
}

/****************************************************************************
名称: read_AO_res(void)
说明: 功能码0x03调用返回
参数: 		           
返回:       
*****************************************************************************/
static int read_AO_res(uint16_t sn, uint16_t start_addr, uint16_t size, uint8_t *p_dst)
{
    uint16_t i;
    uint8_t buf[256];
    modbus_page_t *page = NULL;
    uint16_t end_addr, res_addr;

    if (size == 0 || p_dst == NULL || sn >= dev_num)
        return -1;

    page = &dev_page[sn];

    end_addr = size / 2 + start_addr;
    for (res_addr = start_addr; res_addr < end_addr; )
    {
        for (i = 0; i < page->table_num; i++)
        {
            if (page->table[i].addr == res_addr)
            {
                if ((page->table[i].RW & (1 << 0)) == 0)  //属性不可读，跳过
                    continue;

                if (page->table[i].callback != NULL)
                {
                    bytes_reverse(p_dst, buf, page->table[i].num * 2);
                    page->table[i].callback(sn, buf, page->table[i].num);
                }

                if (page->table[i].offset != NULL)
                {
                    modbus_data_switch(&page->table[i], p_dst);
                }
                res_addr += page->table[i].num;
                p_dst += page->table[i].num * 2;
                break;
            }
        }
        if (i >= page->table_num)
        {
            res_addr++;
            p_dst += 2;            
        }
    }
    return 0;
}

/****************************************************************************
名称: read_input_AO_res(void)
说明: 功能码0x03调用返回
参数: 		           
返回:       
*****************************************************************************/
static int read_input_AO_res(uint16_t sn, uint16_t start_addr, uint16_t size, uint8_t *p_dst)
{
    uint16_t i;
    uint8_t buf[256];
    modbus_page_t *page = NULL;
    uint16_t end_addr, res_addr;

    if (size == 0 || p_dst == NULL || sn >= dev_num)
        return -1;

    page = &dev_page[sn];

    end_addr = size / 2 + start_addr;
    for (res_addr = start_addr; res_addr < end_addr; )
    {
        for (i = 0; i < page->table_num; i++)
        {
            if (page->table[i].addr == res_addr)
            {
                if ((page->table[i].RW & (1 << 0)) == 0)  //属性不可读，跳过
                    continue;

                if (page->table[i].callback != NULL)
                {
                    bytes_reverse(p_dst, buf, page->table[i].num * 2);
                    page->table[i].callback(sn, buf, page->table[i].num);
                }

                if (page->table[i].offset != NULL)
                {
                    modbus_data_switch(&page->table[i], p_dst);
                }
                res_addr += page->table[i].num;
                p_dst += page->table[i].num * 2;
                break;
            }
        }
        if (i >= page->table_num)
        {
            res_addr++;
            p_dst += 2;            
        }
    }
    return 0;
}

int white_more_AO(uint16_t addr_sn, uint16_t res_addr, uint8_t *p_dst)
{
    uint16_t i = 0;
    uint8_t value[256];
    uint16_t tem_U16;
    uint32_t tem_U32;
    float    tem_float;
    for (i = 0; i < dev_page[addr_sn].table_num; i++)
    {
        if (dev_page[addr_sn].table[i].addr == res_addr)
        {
            if (dev_page[addr_sn].table[i].RW != MD_RW && dev_page[addr_sn].table[i].RW != MD_WO)
                return -1;

            if (dev_page[addr_sn].table[i].callback != NULL)
            {
                dev_page[addr_sn].table[i].callback(addr_sn, 
                (uint8_t *)&tem_U16, dev_page[addr_sn].table[i].num * 2);
                bytes_reverse((uint8_t *)&tem_U16, value, 2);
            }
            else
            {
                if (dev_page[addr_sn].table[i].res_data_type == TLV_USHORT &&
                    dev_page[addr_sn].table[i].rel_data_type == TLV_FLOAT)
                {
                    memcpy(&tem_float, dev_page[addr_sn].table[i].offset, sizeof(float));
                    tem_U16 = (uint16_t)(tem_float * dev_page[addr_sn].table[i].ratio + 0.5f);
                    bytes_reverse((uint8_t *)&tem_U16, value, 2);
                }
                else if (dev_page[addr_sn].table[i].res_data_type == TLV_UINT &&
                         dev_page[addr_sn].table[i].rel_data_type == TLV_UINT)
                {
                    tem_U32 = (uint32_t)(*(uint32_t *)dev_page[addr_sn].table[i].offset *
                                         dev_page[addr_sn].table[i].ratio);
                    bytes_reverse((uint8_t *)&tem_U32, value, 4);
                }
            }
            return white_more_AO_push(dev_page[addr_sn].md_addr, res_addr, dev_page[addr_sn].table[i].num,
                                      value, dev_page[addr_sn].table[i].num * 2, p_dst);
        }
    }
    return -1;
}
/****************************************************************************
名称: white_one_AO(void)
说明: 功能码0x06调用
参数: 		           
返回:       
*****************************************************************************/
static int white_more_AO_push(uint8_t addr, uint16_t res_addr, uint16_t res_num,
                  uint8_t *value, uint8_t value_len, uint8_t *p_dst)
{
    uint16_t crc_16;
    uint16_t len = 0;

    if (p_dst == NULL)
        return -1;
    Mstart_addr = res_addr;

    p_dst[len++] = addr;
    p_dst[len++] = MODBUS_WRITE_MULTIPLE_REGISTERS;
    bytes_reverse((uint8_t *)&res_addr, &p_dst[len], 2);
    len += 2;
    bytes_reverse((uint8_t *)&res_num, &p_dst[len], 2);
    len += 2;
    p_dst[len++] = value_len;
    memcpy(&p_dst[len], (uint8_t *)value, value_len);       //数据区大小端转换上层修改
    len += value_len;
    crc_16 = (uint16_t)UART_CRC16_Work(p_dst, len);
    bytes_reverse((uint8_t *)&crc_16, &p_dst[len], 2);
    len += 2;

    return len;
}

/****************************************************************************
名称: white_one_AO_res(void)
说明: 功能码0x06调用返回
参数: 		           
返回:       
*****************************************************************************/
static int white_more_AO_res(uint16_t sn, uint8_t *p_dst)
{
    if (p_dst == NULL || sn >= dev_num)
        return -1;
    
    return 0;
}

/****************************************************************************
名称: check_modbus_frame_valid(uint8_t *p_data, uint8_t len)
说明: 查验报文是否符合规则
参数: 		           
返回:       
*****************************************************************************/
bool check_modbus_frame_valid(uint8_t *p_data, uint8_t len, ModBus_info *info)
{
    uint16_t c_crc16, r_crc16;
    uint8_t revData[15];
	
	memcpy(revData, (uint8_t *)p_data, len);
	
    if (p_data == NULL || len == 0)
        return false;

    if (len < 5) //modbus最短字节
        return false;

    c_crc16 = UART_CRC16_Work(p_data, len - 2);
    bytes_reverse((uint8_t *)&p_data[len - 2], &r_crc16, 2);
    //r_crc16 = *(uint16_t *)&p_data[len - 2];

    if (c_crc16 != r_crc16)
        return false;

    if (p_data[1] & 0x80)
    {
        // log_str(LOG_WARN, "Modebus failure recovery Code = %hhu, word = %hhu",
        //         p_data[1] ^ 0x80, p_data[2]);
        return false;
    }
    info->mod_addr = p_data[0];
    info->func_code = p_data[1];
	if (info->func_code == MODBUS_READ_INPUT_REGISTERS)
	{
		info->Quantity = (p_data[2] << 8) + p_data[3];
		info->Quantity *= 2;
	}
	else
		info->Quantity = p_data[2];
    return true;
}

bool modbus_mast_decode(uint8_t *p_data, uint8_t len, uint16_t offset)
{
    ModBus_info info;

    if (p_data == NULL || len == 0)
        return false;
	
	p_data += 1; //去除头0x00（Keller返回帧首尾多个0x00）
//	if(len > 1) 
//	{
//		len = len-2;
//		
//		if(len > 10)
//		{
//			SWITCH_ON_OFF(BUZZER, SWITCH_ON);	//开机响一声作为自检
//			SoftDelay_ms(500);
//			SWITCH_ON_OFF(BUZZER, SWITCH_OFF);
//			return false;
//		}
//	}
		
    if (check_modbus_frame_valid(p_data, len, &info) == false)
    {
        return false;
    }

//    if (dev_page[offset].md_addr != info.mod_addr)
//    {
//        // log_str(LOG_WARN, "Modebus failure addresses do not match: group_addr: %s, rx_addr:%d",
//        //         dev_page[offset].com_addr, info.mod_addr);
//        return false;
//    }
	
	switch (info.mod_addr)
    {
		case 0x08:       // device md addr.
			offset = 0;
			break;
		case 0x0A:
			offset = 1;
			break;
		case 0x0D:
			offset = 2;
			break;
		default:
			break;
    }

    switch (info.func_code)
    {
		case MODBUS_READ_HOLDING_REGISTERS:
			if (read_AO_res(offset, Mstart_addr, info.Quantity, p_data + 3) != 0)
				return false;
			break;
		case MODBUS_READ_INPUT_REGISTERS:
			if (read_input_AO_res(offset, Mstart_addr, info.Quantity, p_data + 4) != 0)
				return false;
			break;
		case MODBUS_WRITE_MULTIPLE_REGISTERS:
			if (white_more_AO_res(offset, p_data + 1) != 0)
				return false;
			break;
		default:
			break;
    }
    return true;
}
